#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 crane <crane@his-pc>
#
# Distributed under terms of the MIT license.

"""
    給定一个矩阵, 返回正交归一化后的结果
"""

from matrix_tools import *
from dot_cross_product import *


class MatrixExceptin(Exception): pass


class OrthoNormalize:
    def __init__(self, input_mat):
        self.input_mat = input_mat
        self.output_mat = []
        self.rows, self.cols = size(input_mat)
        if self.rows != self.cols:
            raise MatrixExceptin('Is not a square matrix')

        if self.rows == 0:
            return

        self.ortho_normal()

    def ortho_normal(self):
        v0 = normalize(self.input_mat[0])
        self.output_mat.append(v0)

        for i in range(1, self.rows):
            self.handle_row(i)

    def handle_row(self, idx):
        row = self.input_mat[idx]

        # proj_vectors = [proj_vector(row, self.input_mat[i]) for i in range(0, idx)]       # ERROR
        # 不可以投影在原来的vector上, 只可以投影到已经orthonomal的vector上!
        proj_vectors = [proj_vector(row, self.output_mat[i]) for i in range(0, idx)]
        remain = row
        for v in proj_vectors:
            remain = make_vector(v, remain)     # remain - v

        # print('remain [%s]' % remain)
        norm = normalize(remain)
        self.output_mat.append(norm)


def test():
    # l = [
    #     [3, 0, 0],
    #     [0, 4, 0],
    #     [0, 0, 5],
    # ]

    # l = [
    #     [1, 2],
    #     [3, 4],
    # ]

    # l = [
    #     [1, 1],
    #     [1, -1],
    # ]

    l = [
        [1, -1, 1],
        [1, 0, 1],
        [1, 1, 2],
    ]

    # a1, a2 = v = normalize([1, 2])
    # print(v)
    # print(a1 * a1 + a2 * a2)
    # print(1/a1, 2/a2)

    from pprint import pprint

    on = OrthoNormalize(l)
    pprint(on.output_mat)

    onT = transpose_matrix(on.output_mat)

    # orthonomal矩阵的 * on_T 得到identity矩阵(转置即为逆)
    print('===================  =====================')
    m = multiply(on.output_mat, onT)
    pprint(m)
    assert(is_identity(m))


def main():
    test()
    print("start main")

if __name__ == "__main__":
    main()
